{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "# Python代码结构\n",
    "讲解如何组织代码和数据。\n",
    "\n",
    "## 语法和句法\n",
    "\n",
    "### 注释\n",
    "\n",
    "在Python中使用`#`字符标记注释，从`#`开始到当前行结束的部分都是注释。可以把注释作为单独的一行或者把注释和代码放在同一行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "print(\"Hello, World!\")  # 这是一个单行注释"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 把语句分成多行写\n",
    "有时候一行代码太长，我们想分开，或者是出于美观、清晰的需要，可以用`\\`来连接多行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "if (1 == 1) and \\\n",
    "   (2 == 2):\n",
    "    print('Frivolous!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 使用`:`将代码块的头和身体分开"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "if (user == 'green'):       # 头\n",
    "    print('hello, green')   # 身体"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 缩进\n",
    "\n",
    "前面讲过，Python使用缩进来表示代码的逻辑结构，建议使用4个空格进行缩进（可参考[PEP8 Python编码规范](https://www.python.org/dev/peps/pep-0008/)）。\n",
    "\n",
    "### 同一行写多个语句\n",
    "\n",
    "同一行写多个语句，使用`;`分隔。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "import sys; x = 'foo'; sys.stdout.write(x + '\\n')\n",
    "# 这样可行但并不好，降低了代码的可读性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## `if`-`elif`-`else`语句"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "today = input(\"Input: \")\n",
    "\n",
    "if today == 'Mon':\n",
    "    print('Today is Monday')\n",
    "elif today == 'Tue':\n",
    "    print('Today is Tuesday')\n",
    "elif today == 'Wed':\n",
    "    print('Today is Wednesday')\n",
    "else:\n",
    "    print('Today is a boring day')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "`elif` 和C语言中的`else if`是等效的，C语言中的`switch case`结构在Python中没有等效的实现。\n",
    "\n",
    "C语言中使用`if`和`else`最常见的一个问题就是**else悬挂**，很多时候初学者弄不清除哪个`else`和哪个`if`是一对（C语言中，任何一个`else`与其上方最近的一个`if`是一对）。这个问题在Python中不存在，之前我们说过，Python中的缩进所起到的作用不仅仅上是排版层面上的，更是逻辑层面上的。没有了大括号，使用缩进来控制流程的层次深度，便使得程序员无需考虑悬挂问题，只要**保证同样逻辑层次的语句有相同的缩进量**即可："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "if username_is_right:\n",
    "    if passwd_is_right:\n",
    "        if cash > 0:\n",
    "            print(\"you have extra money\")\n",
    "        else:\n",
    "            print(\"you are in debt\")\n",
    "    else:\n",
    "        print(\"wrong password\")\n",
    "else:\n",
    "    print(\"username is not existed!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 条件表达式（三元操作符）\n",
    "\n",
    "语法：`X if C else Y`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "x, y = 3, 4\n",
    "small = x if x < y else y\n",
    "small"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 多重比较\n",
    "\n",
    "如果想同时进行多重比较判断，可使用布尔操作符`and`、`or`或者`not`连接来决定最终表达式的布尔取值。布尔操作符的优先级没有比较表达式的代码段高，即，表达式要先计算然后再比较。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "x = 7\n",
    "x > 5 and x < 10   # True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "避免混淆的办法是加圆括号。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "(x > 5) or not (x < 10)  # True"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 什么是真值\n",
    "\n",
    "下面的情况会被认为是**False**：\n",
    "\n",
    "| 布尔     | False   |\n",
    "|----------|---------|\n",
    "| null类型 | `None`  |\n",
    "| 整型     | `0`     |\n",
    "| 浮点型   | `0.0`   |\n",
    "| 空字符串 | `''`    |\n",
    "| 空列表   | `[]`    |\n",
    "| 空元组   | `()`    |\n",
    "| 空字典   | `{}`    |\n",
    "| 空集合   | `set()` |\n",
    "\n",
    "剩下的都会被认为是`True`。\n",
    "\n",
    "如果是在判断一个表达式，Python会先计算表达式的值，然后返回布尔型结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## `while`循环\n",
    "语法：\n",
    "```python\n",
    "while expression:\n",
    "    loop code\n",
    "```\n",
    "\n",
    "无限循环：\n",
    "```python\n",
    "white True:\n",
    "    ...\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## `for`循环\n",
    "\n",
    "`for`循环是Python中最强大也最使用广泛的循环类型。\n",
    "它可以遍历序列成员，由此可用于列表解析和生成器表达式中。\n",
    "\n",
    "语法：\n",
    "```python\n",
    "for item_var in iterable:    # iterable是可迭代的对象\n",
    "    code to process item_var\n",
    "```\n",
    "\n",
    "一些例子：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Liu, Walter\n",
      "Liu, Nicole\n",
      "Liu, Steven\n",
      "Walter Lim\n",
      "Nicole Lim\n",
      "Steven Lim\n"
     ]
    }
   ],
   "source": [
    "nameList = ['Walter', 'Nicole', 'Steven']\n",
    "# 使用序列索引迭代\n",
    "for nameIndex in range(len(nameList)):\n",
    "    print(\"Liu,\", nameList[nameIndex])\n",
    "\n",
    "# 使用序列项迭代\n",
    "for eachName in nameList:\n",
    "    print(eachName, 'Lim')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## `break`, `continue`, `pass`\n",
    "和C语言中一样，`break`用于终止循环，可以使得流程跳出所在的`while`或者`for`循环。\n",
    "\n",
    "和C语言中一样，`continue`用于终止当前循环，忽略剩下的语句，\n",
    "回到循环开始（即终止当前循环，开始下一次循环）。\n",
    "\n",
    "顾名思义，pass就是什么都不做，通常用作占位符，在函数原型设计中很有用：\n",
    "\n",
    "```python\n",
    "# main function\n",
    "def main():\n",
    "    pass  # 以后有功夫再来完善吧\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### for...in... 的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "for i in (1, 2, 3):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除了list、tuple这样的类型外，dict这种没有下标的类型也可以使用for："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = {'a':1, 'b':2, 'c':3}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a\n",
      "b\n",
      "c\n"
     ]
    }
   ],
   "source": [
    "for i in d:\n",
    "    print(d[i])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_values([1, 2, 3])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.values()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dict_items([('a', 1), ('b', 2), ('c', 3)])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d.items()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in d.values():\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a 1\n",
      "b 2\n",
      "c 3\n"
     ]
    }
   ],
   "source": [
    "for k, v in d.items():\n",
    "    print(k, v)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "str类型也可以使用for："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "A\n",
      "B\n",
      "C\n"
     ]
    }
   ],
   "source": [
    "for ch in 'ABC':\n",
    "     print(ch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n"
     ]
    }
   ],
   "source": [
    "for i in {1, 2, 3}:\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "只要是一个可迭代对象，就可以使用for循环。\n",
    "\n",
    "如何判断是否是可迭代对象？\n",
    "\n",
    "通过collections模块的Iterable类型判断："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import Iterable\n",
    "# isinstance('abc', Iterable) # str是否可迭代\n",
    "# isinstance([1,2,3], Iterable) # list是否可迭代\n",
    "# isinstance(123, Iterable) # 整数是否可迭代\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "那么，如果要对list实现类似Java那样的下标循环怎么办？\n",
    "\n",
    "Python内置的enumerate函数可以把一个list变成索引-元素对，这样就可以在for循环中同时迭代索引和元素本身："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 Walter Lee\n",
      "2 Nicole Lee\n",
      "3 Steven Lee\n"
     ]
    }
   ],
   "source": [
    "# 使用项和索引迭代\n",
    "for i, eachLee in enumerate(nameList):\n",
    "    print(\"%d %s Lee\" % (i+1, eachLee))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. Python 中的for ... in... 使用灵活，不局限下标\n",
    "2. 凡是可以使用for循环遍历的对象，都是可迭代对象"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## 推导式（Comprehensions）\n",
    "\n",
    "是Python内置的非常简单却强大的可以用来创建数据的生成式。\n",
    "\n",
    "推导式是从一个或者多个迭代器快速简洁地创建数据结构的一种方法，\n",
    "最早来源于Haskell编程语言，它可以将循环和条件判断结合，从而避免语法冗长的代码。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[1, 2, 3, 4, 5]\n",
    "list('12345')\n",
    "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "range(1, 11)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "range(1, 11)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(range(1, 11))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "L = []\n",
    "for x in range(1, 11):\n",
    "    if x % 2 == 0:\n",
    "        L.append(x * x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "L"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x * x for x in range(1, 11)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[-1, 4, -3, 16, -5, 36, -7, 64, -9, 100]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x * x if x % 2 == 0 else -x for x in range(1, 11)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Aax',\n",
       " 'Aay',\n",
       " 'Aaz',\n",
       " 'Abx',\n",
       " 'Aby',\n",
       " 'Abz',\n",
       " 'Acx',\n",
       " 'Acy',\n",
       " 'Acz',\n",
       " 'Bax',\n",
       " 'Bay',\n",
       " 'Baz',\n",
       " 'Bbx',\n",
       " 'Bby',\n",
       " 'Bbz',\n",
       " 'Bcx',\n",
       " 'Bcy',\n",
       " 'Bcz',\n",
       " 'Cax',\n",
       " 'Cay',\n",
       " 'Caz',\n",
       " 'Cbx',\n",
       " 'Cby',\n",
       " 'Cbz',\n",
       " 'Ccx',\n",
       " 'Ccy',\n",
       " 'Ccz']"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x + y + z for x in 'ABC' for y in 'abc' for z in 'xyz']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 列表推导（解析）\n",
    "\n",
    "语法：`[expr for item_var in iterable]`\n",
    "\n",
    "该语句的核心是for循环："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "print([x**2 for x in range(9)])\n",
    "print([ss[::-1] for ss in ('green', 'red', 'blue')])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "扩展语法可以实现条件控制： `[expr for item_var in iterable if cond_expr]`\n",
    "\n",
    "另外，也可增加 `else` 语句：`[expr if cond_expr else else_expr for item_var in iterable]`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "练习1：列表推导式实现100以内17的倍数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "练习2：1-100中，不是3的倍数的数取相反数，其余的数保持不变"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "练习3：L = ['Hello', 'World', 18, 'Apple', None]，将字符串中字母变为小写，其余元素不变"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 字典推导\n",
    "\n",
    "语法：`{key_expr: value_expr for expr in iterable}`\n",
    "\n",
    "类似于列表推导，字典推导也有`if`条件判断以及多个`for`循环迭代语句。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'r': 1, 'e': 2, 'l': 1, 't': 2, 's': 1}"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word = 'letters'\n",
    "letter_counts = {letter: word.count(letter) for letter in set(word)}\n",
    "letter_counts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "[x * x for x in range(1, 11)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [],
   "source": [
    "num = (x * x for x in range(1, 11))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "ename": "StopIteration",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m                             Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-41-c3aa4ea10659>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mnext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mStopIteration\u001b[0m: "
     ]
    }
   ],
   "source": [
    "next(num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "generator"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(num)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### 集合推导\n",
    "\n",
    "与上面列表推导类似。\n",
    "\n",
    "### 生成器表达式\n",
    "\n",
    "一边循环，一边通过计算生成数据的机制，叫做生成器：generator。\n",
    "\n",
    "生成器表达式是对列表解析的扩展，列表解析有一个不足，它一次性生成所有数据，\n",
    "用以创建列表，这样在数据量很大，内存很有限的时候便会造成问题。\n",
    "生成器表达式解决了这个问题，它一次生成一个数据，然后暂停，当下一次使用时，\n",
    "生产出下一个数据，工作的过程就像迭代器一样。\n",
    "\n",
    "语法很简单：`(expr for item_var in iterable if cond_expr)`\n",
    "\n",
    "也就是将列表的`[]`换成`()`即可："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "[x * x for x in range(1, 11)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "generator保存的是算法，每次调用next(num)，就计算出num的下一个元素的值，直到计算到最后一个元素，没有更多的元素时，抛出StopIteration的错误。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "**注意：**一个生成器只能运行一次，其只在运行中产生值，不会被存下来，\n",
    "所以不能重新使用或者备份一个生成器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "num = (x * x for x in range(1, 11))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "isinstance(num, Iterable)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "4\n",
      "9\n",
      "16\n",
      "25\n",
      "36\n",
      "49\n",
      "64\n",
      "81\n",
      "100\n"
     ]
    }
   ],
   "source": [
    "for num in num:\n",
    "    print(num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = list(range(1, 11))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "l1 = iter(l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(l1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "## 迭代器和`iter()`函数\n",
    "\n",
    "### 什么是迭代器\n",
    "\n",
    "迭代器是一种特殊的数据结构，在Python中，它也是以对象的形式存在的。\n",
    "迭代器提供了一种遍历类序列对象的方法。\n",
    "对于一般的序列类型，可以利用索引从0一直迭代到序列的最后一个元素；\n",
    "对于字典、文件、自定义对象类型等，可以自定义迭代方式，从而实现对这些对象类型的遍历。\n",
    "\n",
    "可以这样理解：\n",
    "可以被next（）调用并不断返回下一个值的对象，称为迭代器。\n",
    "\n",
    "对于一个集体中的每一个元素，要进行遍历，\n",
    "那么针对这个集体的迭代器定义了遍历每一个元素的顺序或者方法。\n",
    "例如：0, 1, 2, 3, 4...，或者1, 3, 5, 7, 9...\n",
    "\n",
    "### 如何迭代\n",
    "\n",
    "迭代器有一个`__next__()`方法，每次调用这个方法而实现计数（计数不是通过索引实现的），\n",
    "在循环中，如果要获得下一个对象，迭代器自己调用`__next__()`方法，这个过程是透明的。\n",
    "当遍历结束后（集合中再无未访问的项）会遇到`StopIteration`异常，从而结束循环。\n",
    "\n",
    "迭代器有一些限制，只能向前迭代，不能后退，即**迭代是单向的**，当然，\n",
    "可以独立创建一个反向的迭代器。迭代器不能复制，一旦需要重新迭代某个对象，\n",
    "必须重新创建一个该对象的迭代器。\n",
    "\n",
    "`reversed()`返回一个序列对象的逆序迭代器。\n",
    "`enumerate()`也可以返回迭代器。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用迭代器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "生成器都是Iterator对象，但list、dict、str虽然是Iterable，却不是Iterator。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "### `iter()`函数\n",
    "\n",
    " `iter(obj)`  如果`obj`是一个序列类型，那么可以根据其索引从0开始迭代。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "mylist = ['green', 'red', 'blue', 'white']\n",
    "i = iter(mylist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'green'"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ri = reversed(mylist)  # reversed返回一个逆序迭代器\n",
    "next(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'white'"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "next(ri)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 小结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "凡是可作用于for循环的对象都是Iterable类型；\n",
    "\n",
    "凡是可作用于next( )函数的对象都是Iterator类型，它们表示一个惰性计算的序列；\n",
    "\n",
    "集合数据类型如list、dict、str等是Iterable但不是Iterator，不过可以通过iter()函数获得一个Iterator对象。\n",
    "\n",
    "Python的for循环本质上就是通过不断调用next()函数实现的，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for x in [1, 2, 3, 4, 5]:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数是一种代码的抽象方式，可以把大型的代码组织成可管理的代码段，实现代码复用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "依次输入关键字def 、函数名、带有函数参数的圆括号,最后紧跟一个冒号( : ),然后，在缩进块中编写函数体，语法格式：\n",
    "\n",
    "                     def <func_name>(<formal parameters>):\n",
    "                           return <return expression>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def do_noting():\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`def`是定义函数的关键字。\n",
    "\n",
    "Python`函数命名规范`和变量命名一样（必须使用字母或者下划线`_`开头，仅能含有字母、数字和下划线）。上面代码示例中的`pass`表明函数没有做任何事情，仅用来进行占位。\n",
    "\n",
    "函数后面的括号中声明参数名称，**括号，冒号不能一定不能省略**\n",
    "\n",
    "**函数体开始必须缩进**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数调用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "语法格式：**函数名称()**,括号中传入参数值。调用函数时,Python 会执行函数内部的代码，函数执行完之后，返回到主程序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello,world!\n"
     ]
    }
   ],
   "source": [
    "#示例1\n",
    "def print_things():\n",
    "    print('hello,world!')\n",
    "\n",
    "print_things()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 变量可以指向函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = print_things"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4588875016"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(print_things)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4588875016"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id(f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "hello,world!\n"
     ]
    }
   ],
   "source": [
    "f()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "print_things = 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 函数名也是变量"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 参数的传递"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数的参数传递的本质上就是：从实参到形参的赋值操作。Python中“一切皆对象”，所有赋值操作都是“引用的赋值”。所以，Python中参数的传递都是“引用传递”，不是“值传递”。具体操作时一般分为两类：\n",
    "1. 传递可变对象的引用\n",
    "2. 传递不可变对象的引用\n",
    "\n",
    "可变对象：字典、列表、集合等\n",
    "\n",
    "不可变对象：数字、字符串、元组等"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 传递可变对象的引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = [1,2]\n",
    "print(id(b))\n",
    "\n",
    "def test0(m):\n",
    "    print(id(m))\n",
    "    m.append(3)\n",
    "    print(id(m))\n",
    "    print(m)\n",
    "\n",
    "test0(b)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "传递参数是可变对象（例如：列表、字典等），实际传递的是对象的引用，在函数体中不创建新的对象拷贝，而是可以直接修改所传递的对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 传递不可变对象的引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4551939488\n",
      "4551939488\n",
      "13\n",
      "12\n"
     ]
    }
   ],
   "source": [
    "b = 12\n",
    "print(id(b))\n",
    "\n",
    "def test0(m):\n",
    "    print(id(m))\n",
    "    m += 1\n",
    "    print(m)\n",
    "\n",
    "test0(b)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4551945504\n",
      "4551945504\n",
      "4588287504\n",
      "300\n",
      "200\n"
     ]
    }
   ],
   "source": [
    "a = 200\n",
    "print(id(a))\n",
    "\n",
    "def test0(m):\n",
    "    print(id(m))\n",
    "    m = m + 100\n",
    "    print(id(m))\n",
    "    print(m)\n",
    "\n",
    "test0(a)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "传递参数是不可变对象（例如：int，float，字符串、元组、布尔值），实际传递的还是对象的引用。在“赋值操作”时，由于不可变对象无法修改，系统会新创建一个对象。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 函数参数类型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 位置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "test0() missing 1 required positional argument: 'arg2'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-71-cf1c95114335>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;31m# test0(12,10)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mtest0\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m12\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m: test0() missing 1 required positional argument: 'arg2'"
     ]
    }
   ],
   "source": [
    "a = 12\n",
    "b = 10\n",
    "def test0(arg1, arg2):\n",
    "    return arg1 + arg2\n",
    "\n",
    "# test0(12,10)\n",
    "test0(12)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数调用时，实参默认按位置顺序传递，需要个数和形参匹配。按位置传递的参数，称为：“位置参数”"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 关键字参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "def test0(a,b,c):\n",
    "    print(a,b,c)\n",
    "\n",
    "test0(1,2,3)\n",
    "test0(a = 1,c = 3,b = 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "调用函数时可以指定对应参数的名字，可以采用于与函数定义时形参列表不同的顺序调用。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 指定默认参数值"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 10 11\n",
      "1 2 3 11\n",
      "1 2 3 4\n"
     ]
    }
   ],
   "source": [
    "def test0(a,b,c = 10,d = 11):\n",
    "    print(a,b,c,d)\n",
    "\n",
    "test0(1,2)\n",
    "test0(1,2,3)\n",
    "test0(1,2,3,4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当位置参数和关键字参数同时存在时，关键字参数必须放到位置参数的后面。\n",
    "\n",
    "调用函数时如果没有提供关键字参数的参数值时，将使用函数定义时的默认参数值。\n",
    "\n",
    "如果调用函数时提供关键字参数的参数值，则将代替默认值。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**注意：**函数的关键字参数的参数值在函数定义时已经计算出来了，而不是在函数运行时。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n"
     ]
    }
   ],
   "source": [
    "num = 1\n",
    "def test0(arg1=num):\n",
    "    print(arg1)\n",
    "num = 2\n",
    "test0()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所以，在定义函数时，不要把可变的数据类型（列表、字典）当作关键字参数的参数值。函数的关键字参数只会被求值一次，不管函数被怎么调用，当关键字参数的参数值是可变对象时，在函数体中如果其值被改变，再次调用函数时其默认值就是改变后的值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1]\n",
      "[1, 2]\n",
      "[1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "def test0(n, alist=[]):\n",
    "    alist.append(n)\n",
    "    return alist\n",
    "\n",
    "print(test0(1))\n",
    "print(test0(2)) #[1, 2]\n",
    "print(test0(3)) #[1, 2, 3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如何避免这种情况？\n",
    "\n",
    "`None`是个内置常量，当然不能被改变，每次函数bar()被调用就会用这个值给alist赋值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1]\n",
      "[2]\n",
      "[3]\n"
     ]
    }
   ],
   "source": [
    "def test0(n, alist=None):\n",
    "    if alist is None:\n",
    "        alist = []\n",
    "    alist.append(n)\n",
    "    return alist\n",
    "\n",
    "print(test0(1)) #[1]\n",
    "print(test0(2)) #\n",
    "print(test0(3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 可变参数--使用 * 收集位置参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_args(*args):\n",
    "    print(args)\n",
    "\n",
    "print_args(3, 2, 1, 'a', 'b', ['c', 'd'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "任意位置参数可以接受任意数量的位置参数。当参数被用在函数内部时，* 将一组可变数量的位置参数集合成参数值的元组。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_more(arg1, arg2, *rest_args):\n",
    "    print(arg1)\n",
    "    print(arg2)\n",
    "    print(rest_args)\n",
    "\n",
    "print_more(3, 2, 1, 'a', 'b', ['c', 'd'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这对于编写接受可变数量的参数的函数非常有用。如果函数同时有限定的位置参数，那么`*args`会收集剩下的参数。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 可变参数--使用 ** 收集关键字参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'arg1': 1, 'arg2': 2, 'arg3': 'a'}\n"
     ]
    }
   ],
   "source": [
    "def print_kwargs(**kwargs):\n",
    "    print(kwargs)\n",
    "\n",
    "print_kwargs(arg1=1, arg2=2, arg3='a')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用 ** 可以将参数收集到一个字典中，参数的名字是字典的键，对应参数的值是字典的值。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 匿名函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sq = lambda x: x * x\n",
    "print(sq(2))\n",
    "\n",
    "print((lambda x: x * x)(2))\n",
    "\n",
    "h = [lambda x: x * 2,lambda x: x * 3]\n",
    "print(h[0](3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "lambda表达式可以用来声明匿名函数。lambda函数是一种简单的、在同一行中定义函数的方法。lambda实际生成了一个函数对象。\n",
    "\n",
    "lambda表达式只允许包含一个表达式，不能包含复杂语句，该表达式的计算结果就是函数的返回值。\n",
    "\n",
    "lambda表达式的基本语法如下：\n",
    "\n",
    "                        lambda arg1，arg2，arg3...: <表达式>\n",
    "                        \n",
    "其arg1/arg2/arg3为函数的参数，<表达式>相当于函数体，函数返回值：表达式的计算结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 装饰器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个 time1 函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is time1\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "def time1():\n",
    "    time.sleep(3)\n",
    "    print('This is time1')\n",
    "time1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is time1\n",
      "3.0042080879211426\n"
     ]
    }
   ],
   "source": [
    "def wrapper():\n",
    "    t1 = time.time()\n",
    "    time1()\n",
    "    t2 = time.time()\n",
    "    print(t2 - t1) \n",
    "wrapper()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1584521028.7430332"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "time.time()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**需求1：**\n",
    "为函数添加新的功能,但不能修改原函数的代码"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "希望每次调用函数时输出函数执行所花费的时间"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def wrapper():\n",
    "    time_start = time.time()\n",
    "    time1()\n",
    "    time_stop = time.time()\n",
    "    print(time_stop - time_start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "wrapper()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**需求2：**\n",
    "为函数添加新的功能,但不能修改原函数的调用方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def timer(func):\n",
    "    def wrapper():\n",
    "        time_start = time.time()\n",
    "        func()\n",
    "        time_stop = time.time()\n",
    "        print(time_stop - time_start)\n",
    "    return wrapper"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is time1\n",
      "3.0036661624908447\n"
     ]
    }
   ],
   "source": [
    "@timer\n",
    "def time1():\n",
    "    time.sleep(3)\n",
    "    print('This is time1')\n",
    "time1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "@timer\n",
    "def time1():\n",
    "    [x * (x +10) for x in range(10000)]\n",
    "    print('This is time2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "This is time2\n",
      "0.0019838809967041016\n"
     ]
    }
   ],
   "source": [
    "time1()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#time1 = timer(time1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "time1()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**总结：**\n",
    "1. 装饰器可以在不改变原函数的定义和调用方式的基础上，增强函数的功能。\n",
    "2. Python内建了专门的装饰器写法，如：@timer"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  },
  "name": "5_code_structure.ipynb",
  "toc": {
   "colors": {
    "hover_highlight": "#ddd",
    "running_highlight": "#FF0000",
    "selected_highlight": "#ccc"
   },
   "moveMenuLeft": true,
   "nav_menu": {
    "height": "463.85px",
    "width": "251.833px"
   },
   "navigate_menu": true,
   "number_sections": false,
   "sideBar": true,
   "threshold": 4,
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false,
   "widenNotebook": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
